home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue36 / mixin / MixInClasses.pas next >
Encoding:
Pascal/Delphi Source File  |  1998-04-27  |  13.0 KB  |  568 lines

  1. unit MixInClasses;
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes, Controls, StdCtrls, ComCtrls, Messages, Windows, Dialogs;
  7.  
  8. type
  9.  
  10.   TSAChangeType = (sacSingleItemChange,
  11.       sacCurrentChange,
  12.       sacMajorChange,
  13.       sacClosingDown);
  14.  
  15.   IKnowsObject = interface(IUnknown)
  16.     function ObjectOfInterface: TObject;
  17.   end;
  18.  
  19.   IStringArrayClient = interface(IKnowsObject)
  20.     procedure StringArrayChange(ChangeType: TSAChangeType);
  21.   end;
  22.  
  23.   TStringArray = class(TPersistent)
  24.   private
  25.     FCurrent:         Integer;
  26.     ClientList:       TList;
  27.     StrList:          TStringList;
  28.     UpdateCount:      Integer;
  29.   private
  30.     function GetCount: Integer;
  31.     function Get(Index: Integer): String;
  32.     procedure NotifyClients(ChangeType: TSAChangeType);
  33.     procedure Put(Index: Integer; const Value: String);
  34.     procedure SetCount(Value: Integer);
  35.     procedure SetCurrent(Index: Integer);
  36.   public
  37.     constructor Create;
  38.     destructor Destroy; override;
  39.     procedure Assign(Source: TPersistent); override;
  40.     procedure AssignTo(Dest: TPersistent); override;
  41.     procedure BeginUpdate;
  42.     procedure Clear;
  43.     procedure EndUpdate;
  44.     procedure RegisterClient(C: IStringArrayClient);
  45.     procedure UnregisterClient(C: IStringArrayClient);
  46.   public
  47.     property Current: Integer read FCurrent write SetCurrent;
  48.     property Count: Integer read GetCount write SetCount;
  49.     property Strings[Index: Integer]: String read Get
  50.       write Put; default;
  51.   end;
  52.  
  53.   TSATrackBar = class(TTrackBar, IStringArrayClient)
  54.   private
  55.     FStringArray:     TStringArray;
  56.   private
  57.     function GetMax: Integer;
  58.     function GetPosition: Integer;
  59.     function GetSelStart: Integer;
  60.     function GetSelEnd: Integer;
  61.     procedure SetStringArray(SA: TStringArray);
  62.     procedure CNHScroll(var Message: TWMHScroll); message CN_HSCROLL;
  63.     procedure CNVScroll(var Message: TWMVScroll); message CN_VSCROLL;
  64.     function _AddRef: Integer; stdcall;
  65.     function _Release: Integer; stdcall;
  66.     function QueryInterface(const IID: TGUID; out Obj): Integer;
  67.       stdcall;
  68.     function ObjectOfInterface: TObject;
  69.   public
  70.     constructor Create(AOwner: TComponent); override;
  71.     destructor Destroy; override;
  72.     procedure StringArrayChange(ChangeType: TSAChangeType);
  73.   public
  74.     property StringArray: TStringArray read FStringArray
  75.         write SetStringArray;
  76.   published
  77.     property Max: Integer read GetMax;
  78.     property Position: Integer read GetPosition;
  79.     property SelStart: Integer read GetSelStart;
  80.     property SelEnd: Integer read GetSelEnd;
  81.   end;
  82.  
  83.   TSAEdit = class(TEdit, IStringArrayClient)
  84.   private
  85.     FStringArray:     TStringArray;
  86.   private
  87.     procedure Change; override;
  88.     procedure CreateWnd; override;
  89.     procedure SetStringArray(SA: TStringArray);
  90.     procedure StringArrayChange(ChangeType: TSAChangeType);
  91.     function _AddRef: Integer; stdcall;
  92.     function _Release: Integer; stdcall;
  93.     function QueryInterface(const IID: TGUID; out Obj): Integer;
  94.       stdcall;
  95.     function ObjectOfInterface: TObject;
  96.   public
  97.     destructor Destroy; override;
  98.   public
  99.     property StringArray: TStringArray read FStringArray
  100.         write SetStringArray;
  101.   end;
  102.  
  103.   TSAListBox = class(TCustomListBox, IStringArrayClient)
  104.   private
  105.     FStringArray: TStringArray;
  106.   private
  107.     procedure SetStringArray(SA: TStringArray);
  108.     procedure StringArrayChange(ChangeType: TSAChangeType);
  109.     procedure CNCommand(var Msg: TWMCommand);
  110.         message CN_COMMAND;
  111.     function _AddRef: Integer; stdcall;
  112.     function _Release: Integer; stdcall;
  113.     function QueryInterface(const IID: TGUID; out Obj): Integer;
  114.       stdcall;
  115.     function ObjectOfInterface: TObject;
  116.   public
  117.     destructor Destroy; override;
  118.   public
  119.     property StringArray: TStringArray read FStringArray
  120.         write SetStringArray;
  121.   end;
  122.  
  123. implementation
  124.  
  125. // -------- TStringArray --------
  126.  
  127. procedure TStringArray.Assign(Source: TPersistent);
  128. var
  129.   I:      Integer;
  130.   Max:    Integer;
  131. begin
  132.   if (Source is TStrings) or (Source is TStringArray) then
  133.   begin
  134.     BeginUpdate;
  135.     try
  136.       Max := TStrings(Source).Count;
  137.       if StrList.Count < Max then
  138.         Max := StrList.Count;
  139.       for I := 0 to (Max - 1) do
  140.         if Source is TStrings then
  141.           StrList[I] := TStrings(Source)[I]
  142.         else
  143.           StrList[I] := TStringArray(Source)[I];
  144.       for I := Max to (StrList.Count - 1) do
  145.         StrList[I] := '';
  146.     finally
  147.       EndUpdate; // which calls NotifyClients
  148.     end;
  149.   end
  150.   else
  151.     inherited Assign(Source);
  152. end;
  153.  
  154. procedure TStringArray.AssignTo(Dest: TPersistent);
  155. begin
  156.   if Dest is TStrings then
  157.   begin
  158.     Dest.Assign(StrList);
  159.     Exit;
  160.   end;
  161.   inherited AssignTo(Dest);
  162. end;
  163.  
  164. procedure TStringArray.BeginUpdate;
  165. begin
  166.   Inc(UpdateCount);
  167. end;
  168.  
  169. procedure TStringArray.Clear;
  170. begin
  171.   if StrList.Count <> 0 then
  172.   begin
  173.     StrList.Clear;
  174.     FCurrent := -1;
  175.     NotifyClients(sacMajorChange);
  176.   end;
  177. end;
  178.  
  179. constructor TStringArray.Create;
  180. begin
  181.   inherited Create;
  182.   ClientList := TList.Create;
  183.   StrList := TStringList.Create;
  184.   FCurrent := -1;
  185. end;
  186.  
  187. destructor TStringArray.Destroy;
  188. var
  189.   I:  Integer;
  190. begin
  191.   for I := ClientList.Count - 1 downto 0 do
  192.     IStringArrayClient(ClientList[I]).
  193.         StringArrayChange(sacClosingDown);
  194.   ClientList.Free;
  195.   StrList.Free;
  196.   inherited Destroy;
  197. end;
  198.  
  199. procedure TStringArray.EndUpdate;
  200. begin
  201.   Dec(UpdateCount);
  202.   if UpdateCount = 0 then
  203.     NotifyClients(sacMajorChange);
  204. end;
  205.  
  206. function TStringArray.GetCount: Integer;
  207. begin
  208.   Result := StrList.Count;
  209. end;
  210.  
  211. function TStringArray.Get(Index: Integer): String;
  212. begin
  213.   Result := StrList[Index];
  214. end;
  215.  
  216. procedure TStringArray.NotifyClients(ChangeType: TSAChangeType);
  217. var
  218.   I:      Integer;
  219. begin
  220.   if UpdateCount = 0 then
  221.     for I := 0 to (ClientList.Count - 1) do
  222.       IStringArrayClient(ClientList[I]).
  223.           StringArrayChange(ChangeType);
  224. end;
  225.  
  226. procedure TStringArray.Put(Index: Integer; const Value: String);
  227. begin
  228.   if StrList[Index] <> Value then
  229.   begin
  230.     StrList[Index] := Value;
  231.     NotifyClients(sacSingleItemChange);
  232.   end;
  233. end;
  234.  
  235. procedure TStringArray.RegisterClient(C: IStringArrayClient);
  236. begin
  237.   //ShowMessage('Connecting ' + C.ObjectOfInterface.ClassName);
  238.   ClientList.Add(Pointer(C));
  239.   C.StringArrayChange(sacMajorChange);
  240. end;
  241.  
  242. procedure TStringArray.SetCount(Value: Integer);
  243. var
  244.   I: Integer;
  245. begin
  246.   if Value <> StrList.Count then
  247.   begin
  248.     if Value < StrList.Count then
  249.       for I := (StrList.Count - 1) downto Value do
  250.         StrList.Delete(I)
  251.     else
  252.       while (StrList.Count < Value) do
  253.         StrList.Add('');
  254.     if (FCurrent = -1) and (Value > 0) then
  255.       FCurrent := 0
  256.     else if (FCurrent <> -1) and (Value = 0) then
  257.       FCurrent := -1
  258.     else if FCurrent > (Value - 1) then
  259.       FCurrent := Value - 1;
  260.     NotifyClients(sacMajorChange);
  261.   end;
  262. end;
  263.  
  264. procedure TStringArray.SetCurrent(Index: Integer);
  265. begin
  266.   if Index <> FCurrent then
  267.   begin
  268.     if Index < 0 then
  269.       Index := 0
  270.     else if Index > (StrList.Count - 1) then
  271.       Index := StrList.Count - 1;
  272.     FCurrent := Index;
  273.     NotifyClients(sacCurrentChange);
  274.   end;
  275. end;
  276.  
  277. procedure TStringArray.UnregisterClient(C: IStringArrayClient);
  278. begin
  279.   //ShowMessage('Disconnecting ' + C.ObjectOfInterface.ClassName);
  280.   ClientList.Remove(Pointer(C));
  281. end;
  282.  
  283. // -------- TSATrackBar --------
  284.  
  285. constructor TSATrackBar.Create(AOwner: TComponent);
  286. begin
  287.   inherited Create(AOwner);
  288.   inherited Max := 0;
  289.   inherited SelEnd := 0;
  290. end;
  291.  
  292. procedure TSATrackBar.CNHScroll(var Message: TWMHScroll);
  293. begin
  294.   inherited;
  295.   if FStringArray <> nil then
  296.     FStringArray.Current := Position;
  297. end;
  298.  
  299. procedure TSATrackBar.CNVScroll(var Message: TWMVScroll);
  300. begin
  301.   inherited;
  302.   if FStringArray <> nil then
  303.     FStringArray.Current := Position;
  304. end;
  305.  
  306. destructor TSATrackBar.Destroy;
  307. begin
  308.   StringArray := nil;
  309.   inherited Destroy;
  310. end;
  311.  
  312. function TSATrackBar.GetMax;
  313. begin
  314.   Result := inherited Max;
  315. end;
  316.  
  317. function TSATrackBar.GetPosition;
  318. begin
  319.   Result := inherited Position;
  320. end;
  321.  
  322. function TSATrackBar.GetSelStart: Integer;
  323. begin
  324.   Result := inherited SelStart;
  325. end;
  326.  
  327. function TSATrackBar.GetSelEnd: Integer;
  328. begin
  329.   Result := inherited SelEnd;
  330. end;
  331.  
  332. procedure TSATrackBar.SetStringArray(SA: TStringArray);
  333. begin
  334.   if SA <> FStringArray then
  335.   begin
  336.     if SA = nil then
  337.     begin
  338.       FStringArray.UnregisterClient(Self);
  339.       FStringArray := nil;
  340.       inherited Max := 0;
  341.       inherited SelEnd := 0;
  342.     end
  343.     else
  344.     begin
  345.       if FStringArray <> nil then
  346.         FStringArray.UnregisterClient(Self);
  347.       FStringArray := SA;
  348.       FStringArray.RegisterClient(Self);
  349.     end;
  350.   end;
  351. end;
  352.  
  353. procedure TSATrackBar.StringArrayChange(ChangeType: TSAChangeType);
  354. begin
  355.   if FStringArray <> nil then
  356.   begin
  357.     case ChangeType of
  358.       sacCurrentChange:
  359.         inherited Position := FStringArray.Current;
  360.       sacMajorChange:
  361.       begin
  362.         if FStringArray.Count = 0 then
  363.         begin
  364.           inherited Max := 0;
  365.           inherited SelEnd := 0;
  366.         end
  367.         else
  368.         begin
  369.           inherited Max := FStringArray.Count - 1;
  370.           inherited SelEnd := inherited Max;
  371.           inherited Position := FStringArray.Current;
  372.         end;
  373.       end;
  374.       sacClosingDown:
  375.         StringArray := nil;
  376.     end;
  377.   end;
  378. end;
  379.  
  380. function TSATrackBar._AddRef: Integer;
  381. begin
  382.   Result := 0;
  383. end;
  384.  
  385. function TSATrackBar._Release: Integer;
  386. begin
  387.   Result := 0;
  388. end;
  389.  
  390. function TSATrackBar.QueryInterface(const IID: TGUID; out Obj):
  391.   Integer;
  392. begin
  393.   Result := 0;
  394. end;
  395.  
  396. function TSATrackBar.ObjectOfInterface: TObject;
  397. begin
  398.   Result := Self;
  399. end;
  400.  
  401. // -------- TSAEdit --------
  402.  
  403. procedure TSAEdit.Change;
  404. begin
  405.   inherited;
  406.   if (FStringArray <> nil) and (FStringArray.FCurrent <> -1) then
  407.     FStringArray[FStringArray.FCurrent] := Text;
  408. end;
  409.  
  410. procedure TSAEdit.CreateWnd;
  411. var
  412.   RO: Boolean;
  413. begin
  414.   inherited CreateWnd;
  415.   RO := (FStringArray = nil) or ReadOnly;
  416.   SendMessage(Handle, EM_SETREADONLY, Ord(RO), 0);
  417. end;
  418.  
  419. destructor TSAEdit.Destroy;
  420. begin
  421.   StringArray := nil;
  422.   inherited Destroy;
  423. end;
  424.  
  425. procedure TSAEdit.SetStringArray(SA: TStringArray);
  426. begin
  427.   if SA <> FStringArray then
  428.   begin
  429.     if SA = nil then
  430.     begin
  431.       FStringArray.UnregisterClient(Self);
  432.       FStringArray := nil;
  433.       Text := '';
  434.       if HandleAllocated then
  435.         SendMessage(Handle, EM_SETREADONLY, Ord(True), 0);
  436.     end
  437.     else
  438.     begin
  439.       if FStringArray <> nil then
  440.         FStringArray.UnregisterClient(Self);
  441.       FStringArray := SA;
  442.       FStringArray.RegisterClient(Self);
  443.     end;
  444.   end;
  445. end;
  446.  
  447. procedure TSAEdit.StringArrayChange(ChangeType: TSAChangeType);
  448. var
  449.   RO:     Boolean;
  450. begin
  451.   if ChangeType = sacClosingDown then
  452.   begin
  453.     StringArray := nil;
  454.     Exit;
  455.   end;
  456.   if FStringArray.Count = 0 then
  457.   begin
  458.     Text := '';
  459.     RO := True;
  460.   end
  461.   else
  462.   begin
  463.     Text := FStringArray[FStringArray.Current];
  464.     RO := ReadOnly;
  465.   end;
  466.   if HandleAllocated then
  467.     SendMessage(Handle, EM_SETREADONLY, Ord(RO), 0);
  468. end;
  469.  
  470. function TSAEdit._AddRef: Integer;
  471. begin
  472.   Result := 0;
  473. end;
  474.  
  475. function TSAEdit._Release: Integer;
  476. begin
  477.   Result := 0;
  478. end;
  479.  
  480. function TSAEdit.QueryInterface(const IID: TGUID; out Obj):
  481.   Integer;
  482. begin
  483.   Result := 0;
  484. end;
  485.  
  486. function TSAEdit.ObjectOfInterface: TObject;
  487. begin
  488.   Result := Self;
  489. end;
  490.  
  491. // -------- TSAListBox --------
  492.  
  493. destructor TSAListBox.Destroy;
  494. begin
  495.   StringArray := nil;
  496.   inherited Destroy;
  497. end;
  498.  
  499. procedure TSAListBox.CNCommand(var Msg: TWMCommand);
  500. begin
  501.   inherited;
  502.   if (Msg.NotifyCode = LBN_SELCHANGE) and (FStringArray <> nil) then
  503.     FStringArray.Current := ItemIndex;
  504. end;
  505.  
  506.  
  507. procedure TSAListBox.SetStringArray(SA: TStringArray);
  508. begin
  509.   if SA <> FStringArray then
  510.   begin
  511.     if SA = nil then
  512.     begin
  513.       FStringArray.UnregisterClient(Self);
  514.       FStringArray := nil;
  515.       Clear;
  516.     end
  517.     else
  518.     begin
  519.       if FStringArray <> nil then
  520.         FStringArray.UnregisterClient(Self);
  521.       FStringArray := SA;
  522.       FStringArray.RegisterClient(Self);
  523.     end;
  524.   end;
  525. end;
  526.  
  527. procedure TSAListBox.StringArrayChange(ChangeType: TSAChangeType);
  528. begin
  529.   case ChangeType of
  530.     sacSingleItemChange:
  531.       Items[FStringArray.Current] :=
  532.           FStringArray[FStringArray.Current];
  533.     sacCurrentChange:
  534.       ItemIndex := FStringArray.Current;
  535.     sacMajorChange:
  536.     begin
  537.       Items.Assign(FStringArray);
  538.       if FStringArray.Count > 0 then
  539.         ItemIndex := FStringArray.Current;
  540.     end;
  541.     sacClosingDown:
  542.       StringArray := nil;
  543.   end;
  544. end;
  545.  
  546. function TSAListBox._AddRef: Integer;
  547. begin
  548.   Result := 0;
  549. end;
  550.  
  551. function TSAListBox._Release: Integer;
  552. begin
  553.   Result := 0;
  554. end;
  555.  
  556. function TSAListBox.QueryInterface(const IID: TGUID; out Obj):
  557.   Integer;
  558. begin
  559.   Result := 0;
  560. end;
  561.  
  562. function TSAListBox.ObjectOfInterface: TObject;
  563. begin
  564.   Result := Self;
  565. end;
  566.  
  567. end.
  568.